#include "ListE.h"
#include <typeinfo>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
  TListE::TListE():length(0), first(NULL) {}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
  TListE::TListE(void *newElement) {
    this->first  = new TNode(newElement);
    this->length = 1;
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
  TListE::TListE(TListE * list) {
      
    this->length = list->Length();
    
    if (!this->length) this->first = NULL;
    else {
      this->first   = new TNode(list->Get(0));
      TNode *cursor = this->first;
      for(int i = 1; i < this->length; i++) {
        TNode *newNode = new TNode(list->Get(i));
        cursor->Next(newNode);
        cursor = newNode;
      }
    }
    
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
  TListE::~TListE() {
      
    TNode *cursor;
    
    while (this->first) {
      cursor = this->first;
      this->first = this->first->Next();
      delete cursor;
    }
    
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
  TNode* TListE::PosNode(int pos) {
      
    TNode *cursor = this->first;
    for (int i = 0; i < pos; i++)
      cursor = cursor->Next();
    return cursor;
    
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
  void TListE::Add(void* newElement) {
      
    TNode *newNode = new TNode(newElement);
    TNode *cursor  = this->first;
    
    if (this->first) {
      while (cursor->Next()) cursor = cursor->Next();
      cursor->Next(newNode);
    }
    else this->first = newNode;
    
    this->length++;
    
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
  void TListE::AddIni(void* newElement) {

    TNode *newNode = new TNode(newElement);
    newNode->Next(this->first);
    this->first = newNode;
    this->length++;

  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
  void TListE::AddNode(TNode *newNode) {

    TNode *cursor  = this->first;

    if (this->first) {
      while (cursor->Next()) cursor = cursor->Next();
      cursor->Next(newNode);
    }
    else this->first = newNode;
    this->length++;

  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
  void TListE::AddNodeIni(TNode *newNode) {

    newNode->Next(this->first);
    this->first = newNode;
    this->length++;
    
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
  void TListE::Delete(int pos) {
      
    if ((pos < 0) || (pos >= this->length)) return;
    
    TNode *cursor = this->first;
    
    if (!pos) this->first = this->first->Next();
    else {
      for (int i = 0; i < pos - 1; i++)
        cursor = cursor->Next();
      TNode *nodeDel = cursor->Next();
      cursor->Next(nodeDel->Next());
      cursor = nodeDel;
    }
    
    delete cursor;

    this->length--;
    
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
  void TListE::Delete(void* value) {
      
    TNode *cursor = this->first, *temp = cursor;
    int pos = 0;
    
    while((cursor) && (cursor->Info() != value)) {
      temp   = cursor;
      cursor = cursor->Next();
      pos++;
    }
    
    if (!pos) this->first = this->first->Next();
    else temp->Next(cursor->Next());
    
    delete cursor;
    
    this->length--;
    
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
  void* TListE::Transfer(int pos) {
      
    if ((pos < 0) || (pos >= this->length)) return NULL;
    
    TNode *cursor = this->first;
    
    if (!pos) this->first = this->first->Next();
    else {
      for (int i = 0; i < pos - 1; i++)
        cursor = cursor->Next();
      
      TNode *nodeDel = cursor->Next();
      cursor->Next(nodeDel->Next());
      cursor = nodeDel;
    }
    
    this->length--;

    void *Info = cursor->Info();
    
    cursor->Info(NULL);
    delete cursor;

    return Info;
    
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
  TNode* TListE::TransferNode(int pos) {

    if ((pos < 0) || (pos >= this->length)) return NULL;

    TNode *cursor = this->first;

    if (!pos) this->first = this->first->Next();
    else {
      for (int i = 0; i < pos - 1; i++)
        cursor = cursor->Next();

      TNode *nodeDel = cursor->Next();
      cursor->Next(nodeDel->Next());
      cursor = nodeDel;
    }

    this->length--;

    cursor->Next(NULL);

    return cursor;

  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
  void TListE::Destroy(int pos) {

    if ((pos < 0) || (pos >= this->length)) return;

    TNode *cursor = this->first;

    if (!pos) this->first = this->first->Next();
    else {
      for (int i = 0; i < pos - 1; i++)
        cursor = cursor->Next();

      TNode *nodeDel = cursor->Next();
      cursor->Next(nodeDel->Next());
      cursor = nodeDel;
    }

    cursor->Info(NULL);
    delete cursor;
    this->length--;

  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
  void TListE::Insert(void* newElement, int pos) {
      
    if ((pos < 0) || (pos > this->length)) return;
    
    TNode *newNode = new TNode(newElement);
    
    if (!pos) {
      newNode->Next(this->first);
      this->first = newNode;
    }
    else {
        
      TNode *cursor  = this->first;
      int    count = 1;
      
      while (count < pos) {
        cursor = cursor->Next();
        count++;
      }
      
      newNode->Next(cursor->Next());
      cursor->Next(newNode);
    }
    
    this->length++;
    
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
  void TListE::InsertNode(TNode *newNode, int pos) {

    if ((pos < 0) || (pos > this->length)) return;

    if (!pos) {
      newNode->Next(this->first);
      this->first = newNode;
    }
    else {

      TNode *cursor  = this->first;
      int    count = 1;

      while (count < pos) {
        cursor = cursor->Next();
        count++;
      }

      newNode->Next(cursor->Next());
      cursor->Next(newNode);
    }

    this->length++;

  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool TListE::Update(void* value, int pos) {
    
  if ((pos < 0) || (pos > this->length)) return false;
  
  this->Delete(pos);
  this->Insert(value, pos);
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
  void* TListE::Get(int pos) {
      
    if ((pos < 0) || (pos >= this->length)) return NULL;
    
    TNode* cursor = this->first;
    
    for (int i = 0; i < pos; i++)
      cursor = cursor->Next();
    
    return cursor->Info();
    
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void TListE::ForEach(TFunctionAction fAction, void *reference = NULL) {
    
  TNode* cursor = this->first;
  
  while (cursor) {
    fAction(cursor, reference);
    cursor = cursor->Next();
  }
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void* TListE::FirstOcurrence(TFunctionConditional fCondition, void *reference = NULL) {
    
  TNode* cursor = this->first;
  bool   finded = false;
  
  while (cursor && !finded) {
    if (fCondition(cursor, reference)) finded = true;
    else cursor = cursor->Next();
  }
  
  return ((finded)? cursor->Info():NULL);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void TListE::AllOcurrence(TFunctionConditional fCondition, TListE &ListT, void *reference = NULL) {
    
  TNode* cursor = this->first;

  if (ListT.Length())
    for (int i = 0; i < ListT.Length(); i++) ListT.Transfer(i);

  while (cursor) {
    if (fCondition(cursor, reference))
      ListT.Add(cursor->Info());
    cursor = cursor->Next();
  }
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void TListE::AllOcurrenceCond(TFunctionConditionalS fCondition, TListE &ListT, void *reference = NULL) {

  TNode* cursor = this->first;

  if (ListT.Length())
    for (int i = 0; i < ListT.Length(); i++) ListT.Transfer(i);

  while (cursor) {
    int condition = fCondition(cursor, reference);
    if      (condition ==  1) ListT.Add(cursor->Info());
    else if (condition == -1) break;
    cursor = cursor->Next();
  }

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int TListE::NumberOcurrence(TFunctionConditional fCondition, void *reference = NULL) {
    
  TNode* cursor = this->first;
  int    number = 0;
  
  while (cursor) {
    if (fCondition(cursor, reference))
      number++;
    cursor = cursor->Next();
  }
  
  return number;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void TListE::OrderList(TFunctionConditional fCondition, void *reference = NULL) {

  for (int i = 0; i < this->length - 1; i++) 
    for (int j = i + 1; j < this->length; j++)
      if (fCondition(this->PosNode(i), this->PosNode(j))) {
         void* TempInfo = this->PosNode(i)->Info();
         this->PosNode(i)->Info(this->PosNode(j)->Info());
         this->PosNode(j)->Info(TempInfo);
      }
  

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void TListE::MergeList(TFunctionConditional fCondition, void *reference = NULL) {

  this->MixList(fCondition, reference, this);
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void TListE::MixList(TFunctionConditional fCondition, void *reference, TListE *array) {

  TListE *array1 = new TListE, *array2 = new TListE;
  int n = array->Length(), n1, n2, i, j;

  if (n > 1) {

    if (n%2 == 0)   n1 = n2 = (int)n/2;
    else         {  n1 = (int)n/2; n2 = n1 + 1; }

    for (i = 0; i < n1; i++)      array1->Add(array->PosNode(i)->Info());
    for (j = 0; j < n2; j++, i++) array2->Add(array->PosNode(i)->Info());
    
    MixList(fCondition, reference, array1);
    MixList(fCondition, reference, array2);
    MixListX(fCondition, reference, array1, array2, array);

  }

  while (array1->Length()) array1->Transfer(0);
  while (array2->Length()) array2->Transfer(0);

  if (array1) delete array1;
  if (array2) delete array2;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void TListE::MixListX(TFunctionConditional fCondition, void *reference, TListE *array1, TListE *array2, TListE *array3) {

  int x1 = 0, x2 = 0, x3 = 0;

  while (x1 < array1->Length() && x2 < array2->Length())
    if (fCondition(array1->PosNode(x1), array2->PosNode(x2))) array3->PosNode(x3++)->Info(array1->PosNode(x1++)->Info());
    else                                                      array3->PosNode(x3++)->Info(array2->PosNode(x2++)->Info());

  while (x1 < array1->Length()) array3->PosNode(x3++)->Info(array1->PosNode(x1++)->Info());
  while (x2 < array2->Length()) array3->PosNode(x3++)->Info(array2->PosNode(x2++)->Info());

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
